#ifndef DIGIT_HPP
#define DIGIT_HPP

#include <opencv2/opencv.hpp>
#include <opencv2/text.hpp>
#include <algorithm>

#include "usbcamera.hpp"



class Digit
{

public:
    static int IsCharacterLinked(cv::Rect charBoundingBox1, cv::Rect charBoundingBox2)
    {

        float widthRatio=((float)charBoundingBox1.width)/((float)charBoundingBox2.width);
        if(widthRatio>2 || widthRatio<0.5)
            return false; //not linked

        float heightRatio=((float)charBoundingBox1.height)/((float)charBoundingBox2.height);
        if(heightRatio>2 || heightRatio<0.5)
            return false;

        cv::Point charCenter1(charBoundingBox1.x+charBoundingBox1.width/2, charBoundingBox1.y+charBoundingBox1.height/2);
        cv::Point charCenter2(charBoundingBox2.x+charBoundingBox2.width/2, charBoundingBox2.y+charBoundingBox2.height/2);

        if(charCenter1.y<charBoundingBox2.y || charCenter1.y>charBoundingBox2.y+charBoundingBox2.height)
            return false;

        if(charCenter2.y<charBoundingBox1.y || charCenter2.y>charBoundingBox1.y+charBoundingBox1.height)
            return false;

        int dx=charCenter2.x-charCenter1.x;

        if(dx>0)
        {
            if(dx>2*charBoundingBox1.width || dx>2*charBoundingBox2.width)
                return false;
            return 1;//linked, char1 first
        }
        
        if(-dx>2*charBoundingBox1.width || -dx>2*charBoundingBox2.width)
            return false;

        return 2;//linked, char2 first
    }

    static int GetCharIndex(char Character,
                            std::string vocabulary = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
            // must have the same order as the clasifier output classes
            )
    {
        size_t index=std::find(vocabulary.begin(),vocabulary.end(),Character)-vocabulary.begin();
        return index;
    }

    static void draw(cv::Mat &canvas, cv::Rect box1, cv::Rect box2)
    {
        cv::rectangle(canvas, box1, cv::Scalar(0,0,255), 5);
        cv::rectangle(canvas, box2, cv::Scalar(0,255,0), 5);
        cv::imshow("canvas",canvas);
        //        cv::waitKey();
    }

    cv::Rect boundingBox;
    std::vector<int> out_classes;
    std::vector<double> out_confidences;

    Digit(cv::Rect boundingBox0)
        : boundingBox(boundingBox0)
    {

    }

    double GetConfidence(int charint)
    {
        size_t index=std::find(out_classes.begin(),out_classes.end(),charint)-out_classes.begin();
        if(index<out_classes.size())
        {
            return out_confidences[index];
        }
        return 0;
    }

    void dp(const cv::Mat &imageGray, std::string winname)
    {
        std::cout<<cv::Mat(out_classes).t()<<"\n"
                <<cv::Mat(out_confidences).t()<<"\n"<<std::flush;

        cv::imshow(winname, imageGray(boundingBox));
        cv::waitKey(10000);
    }

    void Analysis(cv::Mat &imageGray, cv::Ptr<cv::text::OCRHMMDecoder::ClassifierCallback> &ocr)
    {
        ocr->eval(imageGray(boundingBox), out_classes, out_confidences);
    }

    void Analysis(cv::Mat &imageLabel, cv::Ptr<cv::text::OCRHMMDecoder::ClassifierCallback> &ocr, int index)
    {
        cv::Mat labeli;
        cv::compare(imageLabel(boundingBox), index, labeli, cv::CMP_EQ);
        ocr->eval(labeli, out_classes, out_confidences);
    }


    static cv::Rect ExpandRoi(cv::Rect roi, cv::Size imageSize, cv::Size gap=cv::Size(45,45))
    {
        roi.x-=gap.width;
        if(roi.x<0)
            roi.x=0;

        roi.y-=gap.height;
        if(roi.y<0)
            roi.y=0;

        roi.width+=gap.width*2;
        int xborder=imageSize.width-roi.x;
        if(roi.width>xborder)
            roi.width=xborder;

        roi.height+=gap.height*2;
        int yborder=imageSize.height-roi.y;
        if(roi.height>yborder)
            roi.height=yborder;

        return roi;
    }


    static cv::Rect ExpandRoi2(cv::Rect roi, cv::Size imageSize, cv::Size gap=cv::Size(30,30))
    {
        if(gap.width>roi.width*0.5)
            gap.width=roi.width*0.5;

        if(gap.height>roi.height*0.5)
            gap.height=roi.height*0.5;

        return ExpandRoi(roi, imageSize, gap);
    }


    static cv::Rect UnionRoi(cv::Rect roi1, cv::Rect roi2)
    {
        return roi1|roi2;
    }


    static void ToBinary(cv::Mat &mask, const cv::Mat &inputImage, cv::Scalar hsvThres[2])
    {
        cv::Mat hsv;
        cv::cvtColor(inputImage, hsv, CV_BGR2HSV);

        std::cout<<inputImage.size()<<"\n";

        //        cv::Mat mask;

        std::vector<cv::Mat> hsvl;
        cv::split(hsv, hsvl);

#if 1
        cv::Mat gray=hsvl[2];
        //        cv::cvtColor(inputImage, gray, CV_BGR2GRAY);



        cv::resize(gray, gray, cv::Size(), 0.5, 0.5);
        cv::Mat grayo;

        cv::Mat element25a = cv::getStructuringElement(cv::MORPH_ELLIPSE,cv::Size(100,100));
        cv::morphologyEx(gray,grayo,cv::MORPH_TOPHAT,element25a);

        cv::resize(grayo,grayo,inputImage.size());

        //         cv::inRange(grayo, cv::Scalar(hsvThres[0][2]), cv::Scalar(hsvThres[1][2]), mask);
        hsvl[2]=grayo;

#endif


        cv::merge(hsvl, hsv);


#if 1


        //        ExtractYellow(hsv,mask);

        //        cv::inRange(hsv, cv::Scalar(150,-1,150), cv::Scalar(180,256,255), mask);



        if(hsvThres[0][0]>hsvThres[1][0])
        {
            cv::Scalar ht0=hsvThres[0];
            cv::Scalar ht1=hsvThres[1];
            ht0[0]=-1;
            ht1[0]=181;

            cv::Mat mask0;
            cv::inRange(hsv, hsvThres[0], ht1, mask0);

            cv::Mat mask1;
            cv::inRange(hsv, ht0, hsvThres[1], mask1);

            cv::bitwise_or(mask0, mask1, mask);
        }
        else
            cv::inRange(hsv, hsvThres[0], hsvThres[1], mask);
#endif

#ifdef SHOWSEGMENT
        cv::imshow("bw",mask);
        cv::imshow("hsv",hsv);
#endif

    }


    static double LocateP(cv::Mat &inputImage,
                          cv::Ptr<cv::text::OCRHMMDecoder::ClassifierCallback> &ocr, cv::Rect &pBoundingBox, cv::Vec2d corner[4], cv::Scalar hsvThres[2])
    {

        cv::Mat mask;

        ToBinary(mask, inputImage, hsvThres);

        cv::Mat masko;

        cv::Mat element25 = cv::getStructuringElement(cv::MORPH_ELLIPSE,cv::Size(3,3));
        cv::morphologyEx(mask,masko,cv::MORPH_OPEN,element25);


        cv::Mat bw_label,stat,centroid;
        cv::connectedComponentsWithStats(masko,bw_label,stat,centroid);


        cv::Size rcThres(20,20);


        std::vector<Digit> nl;


        std::vector<int> labelIndex;

        for (int i=1;i<stat.rows;i++)
        {
            cv::Rect rc(stat.at<int>(i,cv::CC_STAT_LEFT),stat.at<int>(i,cv::CC_STAT_TOP),stat.at<int>(i,cv::CC_STAT_WIDTH),stat.at<int>(i,cv::CC_STAT_HEIGHT));
            if(rc.width>rcThres.width && rc.height>rcThres.height)
            {
                nl.push_back(Digit(rc));
                nl.back().Analysis(inputImage, ocr);
                labelIndex.push_back(i);
            }
        }

        std::vector<double> confidence;


        for(size_t i=0;i<nl.size();i++)
        {
            confidence.push_back(nl[i].GetConfidence(GetCharIndex('P'))+nl[i].GetConfidence(GetCharIndex('p')));
        }

        if(confidence.empty())
        {
            return 0;
        }


        size_t maxindex=std::max_element(confidence.begin(),confidence.end())-confidence.begin();

        pBoundingBox=nl[maxindex].boundingBox;

        std::cout<<"\nconfidence="<<confidence[maxindex]<<std::flush;


        cv::compare(bw_label, labelIndex[maxindex], masko, cv::CMP_EQ);


        std::vector<std::vector<cv::Point> > contours;
        std::vector<cv::Vec4i> hierarchy;

        cv::findContours( masko, contours, hierarchy, CV_RETR_CCOMP, cv::CHAIN_APPROX_NONE);

        std::vector<std::vector<cv::Point> > contoursap(contours.size(), std::vector<cv::Point>());



        double elw=pBoundingBox.width/7;
        double elh=pBoundingBox.height/9;
        double el=(elw>elh?elh:elw);

        std::cout<<"contoursap="<<contoursap.size()<<"\nel="<<el<<"\n";

        for(size_t i=0;i<contours.size();i++)
        {
            cv::approxPolyDP(contours[i],contoursap[i],el,true);
            //            std::cout<<cv::Mat(contoursap[i])<<"\n";
        }


        std::vector<double> area(contoursap.size());
        for(size_t i=0;i<contoursap.size();i++)
        {
            area[i]=cv::contourArea(contoursap[i]);
        }

        size_t maxareaindex=std::max_element(area.begin(),area.end())-area.begin();


        size_t nc=contoursap[maxareaindex].size();

        if(nc<5) return 0;


        std::vector<cv::Point> contourf;

        contourf.assign(contoursap[maxareaindex].begin(), contoursap[maxareaindex].end());

        size_t tlindex=0;
        size_t blindex=0;

        for(size_t i=1;i<contourf.size();i++)
        {
            if(contourf[i].x<contourf[tlindex].x)
                tlindex=i;
        }


        contourf.erase(contourf.begin()+tlindex);

        for(size_t i=1;i<contourf.size();i++)
        {
            if(contourf[i].x<contourf[blindex].x)
                blindex=i;
        }

        if(blindex>=tlindex) blindex++;

        if(contoursap[maxareaindex][blindex].y<contoursap[maxareaindex][tlindex].y)
        {
            size_t tempind=tlindex;
            tlindex=blindex;
            blindex=tempind;
        }

        corner[0][0]=contoursap[maxareaindex][tlindex].x;
        corner[0][1]=contoursap[maxareaindex][tlindex].y;
        corner[1][0]=contoursap[maxareaindex][blindex].x;
        corner[1][1]=contoursap[maxareaindex][blindex].y;




        int dfindex=(int)tlindex-(int)blindex;

        int n=nc-1;

        size_t indexf[2];

        if(dfindex==1 || dfindex==-n)
        {
            indexf[0]=(blindex+n)%nc;
            indexf[1]=(blindex+n-1)%nc;
        }
        else
        {
            if(dfindex==-1 || dfindex==n)
            {
                indexf[0]=(blindex+1)%nc;
                indexf[1]=(blindex+2)%nc;
            }
            else
            {
                return 0;
            }
        }

        corner[2][0]=contoursap[maxareaindex][indexf[0]].x;
        corner[2][1]=contoursap[maxareaindex][indexf[0]].y;
        corner[3][0]=contoursap[maxareaindex][indexf[1]].x;
        corner[3][1]=contoursap[maxareaindex][indexf[1]].y;

        std::vector<cv::Point2f> pointbuf(4);
        for(int i=0;i<4;i++)
        {
            pointbuf[i].x=corner[i][0];
            pointbuf[i].y=corner[i][1];
        }

        cv::Mat grayImage;
        cv::cvtColor(inputImage, grayImage, CV_BGR2GRAY);


        cv::Mat grayImageBlur;
        cv::blur(grayImage, grayImageBlur, cv::Size(7,7));

        cv::cornerSubPix(grayImageBlur, pointbuf,
                         cv::Size(el/2,el/2),
                         cv::Size(-1,-1),
                         cv::TermCriteria( cv::TermCriteria::EPS+cv::TermCriteria::COUNT, 30, 0.1 ));

        for(int i=0;i<4;i++)
        {
            corner[i][0]=pointbuf[i].x;
            corner[i][1]=pointbuf[i].y;
        }

        //        {cv::Mat canvas=inputImage.clone(); draw(canvas, digitBoundingBox[0], digitBoundingBox[1]);}

        return confidence[maxindex];

    }




    static double TraceP(cv::Mat &inputImage,
                         cv::Ptr<cv::text::OCRHMMDecoder::ClassifierCallback> &ocr, cv::Rect &pBoundingBox, cv::Vec2d corner[4], cv::Scalar hsvThres[2], cv::Size gap=cv::Size(50,50))
    {
        cv::Rect pSearchRegion=ExpandRoi(pBoundingBox, inputImage.size(), gap);

        cv::Mat bgr=inputImage(pSearchRegion);

        double res=LocateP(bgr, ocr, pBoundingBox, corner, hsvThres);

        if(res>0)
        {
            pBoundingBox.x+=pSearchRegion.x;
            pBoundingBox.y+=pSearchRegion.y;

            for(int i=0;i<4;i++)
            {
                corner[i][0]+=pSearchRegion.x;
                corner[i][1]+=pSearchRegion.y;
            }

        }

        return res;
    }


    static void ToBinary2(cv::Mat &bw, const cv::Mat &inputImage, int threshold=180)
    {
        cv::Mat I_gray, tophat;
        //                cv::Mat element25 = cv::getStructuringElement(cv::MORPH_ELLIPSE,cv::Size(25,25));
        cv::cvtColor(inputImage,I_gray,CV_BGR2GRAY);
        //                cv::morphologyEx(I_gray,tophat,cv::MORPH_TOPHAT,element25);

        //                cv::imshow("tophat",tophat);

        tophat=I_gray;

        cv::compare(tophat,threshold, bw,cv::CMP_GT);

        //        cv::threshold(I_gray, bw, 128, 255, cv::THRESH_BINARY|cv::THRESH_OTSU);

    }


    static double LocateTwoDigit(cv::Mat &inputImage, unsigned int number,
                                 cv::Ptr<cv::text::OCRHMMDecoder::ClassifierCallback> &ocr, cv::Rect digitBoundingBox[2], int threshold=180)
    {
        char digit[4];

        int n=sprintf(digit, "%u", number);

        std::cout<<digit<<"\n"<<std::flush;

        int digitint[2]={GetCharIndex(digit[0]), GetCharIndex(digit[1])};

        cv::Size rcThres(10,20);

        //        if(digitint[0]==53 || digitint[1]==53)            rcThres.width=10;

        cv::Mat bw,bw_label,stat,centroid;

//        ToBinary2(bw, inputImage, threshold);


        cv::Scalar hsvThres[2]={
            //            cv::Scalar(150,-1,150), cv::Scalar(180,256,255)
                        cv::Scalar(-1,-1,110), cv::Scalar(256,256,255)
            //            cv::Scalar(150,-1,100), cv::Scalar(20,256,255)
//            cv::Scalar(140,-1,50), cv::Scalar(40,256,255)
        };

        ToBinary(bw, inputImage, hsvThres);



        cv::connectedComponentsWithStats(bw,bw_label,stat,centroid);

        std::vector<Digit> nl;



        for (int i=1;i<stat.rows;i++)
        {
            cv::Rect rc(stat.at<int>(i,cv::CC_STAT_LEFT),stat.at<int>(i,cv::CC_STAT_TOP),stat.at<int>(i,cv::CC_STAT_WIDTH),stat.at<int>(i,cv::CC_STAT_HEIGHT));
            //            int area=stat.at<int>(i,cv::CC_STAT_AREA);
            if(rc.width>rcThres.width && rc.height>rcThres.height)
            {
                nl.push_back(Digit(rc));
                nl.back().Analysis(inputImage, ocr);
            }
        }



        std::vector<double> confidence;
        std::vector< std::vector<size_t> > nbbl;

        for(size_t i=0;i<nl.size();i++)
        {
            for(size_t j=i+1;j<nl.size();j++)
            {
                int res=IsCharacterLinked(nl[i].boundingBox, nl[j].boundingBox);
                switch(res)
                {
                case 1:
                    nbbl.push_back(std::vector<size_t>(1,i));
                    nbbl.back().push_back(j);
                    confidence.push_back(nl[i].GetConfidence(digitint[0])*nl[j].GetConfidence(digitint[1]));

                    //{cv::Mat canvas=inputImage.clone(); draw(canvas, nl[i].boundingBox, nl[j].boundingBox);}

                    break;
                case 2:
                    nbbl.push_back(std::vector<size_t>(1,j));
                    nbbl.back().push_back(i);
                    confidence.push_back(nl[j].GetConfidence(digitint[0])*nl[i].GetConfidence(digitint[1]));

                    //{cv::Mat canvas=inputImage.clone(); draw(canvas, nl[j].boundingBox, nl[i].boundingBox);}

                    break;
                default:
                    break;
                }
            }
        }

        if(confidence.empty())
        {
            return 0;
        }


        size_t maxindex=std::max_element(confidence.begin(),confidence.end())-confidence.begin();

        digitBoundingBox[0]=(nl[nbbl[maxindex][0]].boundingBox);

        digitBoundingBox[1]=(nl[nbbl[maxindex][1]].boundingBox);

        std::cout<<"\nconfidence="<<confidence[maxindex]<<std::flush;

        //        {cv::Mat canvas=inputImage.clone(); draw(canvas, digitBoundingBox[0], digitBoundingBox[1]);}

        return confidence[maxindex];

    }
    
    
    static double TraceTwoDigit(cv::Mat &inputImage, unsigned int number,
                                cv::Ptr<cv::text::OCRHMMDecoder::ClassifierCallback> &ocr, cv::Rect digitBoundingBox[2], int threshold=180, cv::Size gap=cv::Size(30,30))
    {
        cv::Rect digitSearchRegion[2]={
            ExpandRoi(digitBoundingBox[0], inputImage.size(), gap),
            ExpandRoi(digitBoundingBox[1], inputImage.size(), gap)
        };

        cv::Rect roi=digitSearchRegion[0]|digitSearchRegion[1];

        cv::Mat bgr=inputImage(roi);

        double res=LocateTwoDigit(bgr, number, ocr, digitBoundingBox, threshold);

        if(res>0)
        {
            digitBoundingBox[0].x+=roi.x;
            digitBoundingBox[0].y+=roi.y;

            digitBoundingBox[1].x+=roi.x;
            digitBoundingBox[1].y+=roi.y;
        }

        return res;
    }
    
    
    static void FloodFromPoints(cv::Mat &out, const cv::Mat &in, const std::vector<cv::Point> &candidates,
                                bool inverse=true, int flags=4 + (255 << 8) + CV_FLOODFILL_MASK_ONLY,
                                cv::Scalar loDiff=cv::Scalar::all(6), cv::Scalar upDiff=cv::Scalar::all(6))
    {
        cv::Mat mask(in.rows+2,in.cols+2,CV_8UC1,cv::Scalar(0));
        cv::Mat mask1(in.rows+2,in.cols+2,CV_8UC1,cv::Scalar(0));

        for(size_t r=0;r<candidates.size();r++)
        {
            if(mask.at<uchar>(candidates[r].y+1,candidates[r].x+1)==0)
            {
                mask1.setTo(0);
                int area=cv::floodFill(in,mask1,candidates[r],cv::Scalar(255),NULL,loDiff,upDiff,flags);
                cv::bitwise_or(mask,mask1,mask);
            }
        }

        if(inverse)
            cv::bitwise_not(mask(cv::Rect(1,1,in.cols,in.rows)),out);
        else
            mask(cv::Rect(1,1,in.cols,in.rows)).copyTo(out);
        //cv::imshow("res",out);
    }


    static void ExtractYellow(const cv::Mat &hsv, cv::Mat &mask)
    {
        cv::inRange(hsv, cv::Scalar(150,-1,150), cv::Scalar(180,256,255), mask);
    }

    static void drawp(cv::Mat &canvas, cv::Rect pBoundingBox, cv::Vec2d corner[4])
    {

        cv::Rect roie=ExpandRoi(pBoundingBox, canvas.size(), cv::Size(15,15));

        cv::Mat bw3;
        canvas(roie).copyTo(bw3);

        cv::circle(bw3, cv::Point(corner[0][0], corner[0][1])-roie.tl(), 3, cv::Scalar(255,0,0));
        cv::circle(bw3, cv::Point(corner[1][0], corner[1][1])-roie.tl(), 3, cv::Scalar(0,0,255));
        cv::circle(bw3, cv::Point(corner[2][0], corner[2][1])-roie.tl(), 3, cv::Scalar(0,255,0));
        cv::circle(bw3, cv::Point(corner[3][0], corner[3][1])-roie.tl(), 3, cv::Scalar(255,0,255));


        //        cv::putText(bw3, "*", cv::Point(corner[0][0], corner[0][1])-roie.tl(), cv::FONT_HERSHEY_SIMPLEX , 0.8,cv::Scalar(255,0,0));
        //        cv::putText(bw3, "*", cv::Point(corner[1][0], corner[1][1])-roie.tl(), cv::FONT_HERSHEY_SIMPLEX , 0.8,cv::Scalar(0,0,255));
        //        cv::putText(bw3, "*", cv::Point(corner[2][0], corner[2][1])-roie.tl(), cv::FONT_HERSHEY_SIMPLEX , 0.8,cv::Scalar(0,255,0));
        //        cv::putText(bw3, "*", cv::Point(corner[3][0], corner[3][1])-roie.tl(), cv::FONT_HERSHEY_SIMPLEX , 0.8,cv::Scalar(0,255,255));


        cv::imshow("p", bw3);

    }

    static void pic()
    {
        cv::Ptr<cv::text::OCRHMMDecoder::ClassifierCallback> ocr1 = cv::text::loadOCRHMMClassifierCNN("OCRBeamSearch_CNN_model_data.xml.gz");

        cv::Mat mm=cv::imread("canvas_screenshot_16.10.2017.png");


        cv::Mat hsv;
        cv::cvtColor(mm, hsv, CV_BGR2HSV);

        cv::Mat hsvb;
        cv::inRange(hsv, cv::Scalar(14,-1,-1), cv::Scalar(22,256,256), hsvb);


        cv::Mat out;

        FloodFromPoints(out, mm, std::vector<cv::Point>(1, cv::Point(2385,1435)), false, 4 + (255 << 8) + CV_FLOODFILL_MASK_ONLY, cv::Scalar(9,9,9)*1.2, cv::Scalar(9,9,9)*1.2);

        cv::Mat mg;
        cv::cvtColor(mm,mg,CV_BGR2GRAY);
        cv::Mat ml[3]={mg,out,mg};

        cv::Mat om;
        cv::merge(ml,3,om);



        cv::Mat K,D;
        USBCamera::Load(K, "Kf.yml");
        USBCamera::Load(D, "Df.yml");


        cv::Size sznew=mm.size()*4 ;
        cv::Mat Knew=K.clone();
        Knew.at<double>(0,2)=sznew.width/2;
        Knew.at<double>(1,2)=sznew.height/2;


        cv::Mat R;
        cv::Mat rv(3, 1, CV_64FC1, cv::Scalar(0));
        rv.at<double>(0)=20*CV_PI/180;
        cv::Rodrigues(rv, R);


        cv::Mat map1, map2;
        cv::fisheye::initUndistortRectifyMap(K, D, R, Knew, sznew, CV_16SC2, map1, map2);


        std::cout<<"map1="<<map1.size()<<"\n"<<std::flush;
        std::cout<<"map2="<<map2.size()<<"\n"<<std::flush;




        cv::namedWindow("canvas",cv::WINDOW_NORMAL);

        //        cv::VideoCapture c("TV_CAM_device_20171011_092616.mkv");

        //        cv::waitKey();

        double maxdmm=5000;
        double hmm=1630-920-31;
        int h=Knew.at<double>(1,2)-Knew.at<double>(0,0)/maxdmm*hmm;

        //        while(c.read(mm))
        {
            cv::Mat mmu;
            //        cv::fisheye::undistortImage(mm, mmu, K, D, Knew, sznew);

            int64 t0=cv::getTickCount();
            cv::remap(mm, mmu, map1.rowRange(0,h), map2.rowRange(0,h), cv::INTER_LINEAR);

            int64 t1=cv::getTickCount();

            std::cout<<"\nfail="<<(double)(t1-t0)/cv::getTickFrequency()<<std::flush;

            cv::imshow("canvas", hsv);
            cv::waitKey(100000);
        }


        //        c.release();


        //        cv::imwrite("u.png",mmu);

        //        cv::Rect nbb[2];

        //        unsigned num=45 ;

        //         double resp=LocateTwoDigit(mmu, num, ocr1, nbb);


    }


    static void videotestbw(std::string fp="/home/u/Downloads/TV_CAM_设备_20180213_141729.mkv")
    {
        cv::VideoCapture c(fp);

        cv::Mat m;

        cv::Mat bw;

        cv::Scalar hsvThres[2]={
            //            cv::Scalar(150,-1,150), cv::Scalar(180,256,255)
            //            cv::Scalar(-1,-1,110), cv::Scalar(256,256,255)
            //            cv::Scalar(150,-1,100), cv::Scalar(20,256,255)
            cv::Scalar(160,-1,100), cv::Scalar(30,256,255)
        };

        cv::namedWindow("m",CV_WINDOW_NORMAL);
        cv::namedWindow("hsv",CV_WINDOW_NORMAL);
        cv::namedWindow("bw",CV_WINDOW_NORMAL);

        while(c.read(m))
        {
            cv::flip(m.t(),m,0);

            int64 t0=cv::getTickCount();
            ToBinary(bw, m, hsvThres);

            int64 t1=cv::getTickCount();


            cv::imshow("m",m);
            cv::waitKey(1);
        }

        c.release();

    }

    static void videotest(std::string fp="/home/u/Downloads/TV_CAM_设备_20180213_141729.mkv")
    {
        cv::Ptr<cv::text::OCRHMMDecoder::ClassifierCallback> ocr1 = cv::text::loadOCRHMMClassifierCNN("OCRBeamSearch_CNN_model_data.xml.gz");


        cv::VideoCapture c(fp);

        cv::Mat m;

        unsigned num=25;
        int thres=170;
        cv::Size gap(30,30);
        cv::Rect nbb[2];

        double propertyThres=0.1;

        double resp=0;

        cv::namedWindow("m",CV_WINDOW_NORMAL);

        while(c.read(m))
        {
            cv::flip(m.t(),m,0);

            int64 t0=cv::getTickCount();

            if(resp<propertyThres)
                resp=Digit::LocateTwoDigit(m, num, ocr1, nbb, thres);
            else
                resp=Digit::TraceTwoDigit(m, num, ocr1, nbb, thres, gap);

            int64 t1=cv::getTickCount();

            std::cout<<"\nt="<<(double)(t1-t0)/cv::getTickFrequency()<<",\t"<<resp<<"\n"<<std::flush;
            if(resp>propertyThres)
            {
                cv::rectangle(m, nbb[0], cv::Scalar(0,0,255), 5);
                cv::rectangle(m, nbb[1], cv::Scalar(0,255,0), 5);
            }
            cv::imshow("m",m);
            cv::waitKey(1);
        }

        c.release();

    }




};


#endif // DIGIT_HPP

